# -*- coding:utf-8 -*-
__author__ = 'Administrator'
__all__ = ('Transform',)
from kivy.core.window import Window
from kivy.graphics import Scale, Rotate, Translate
from kivy.graphics.transformation import Matrix
from kivy.graphics.context_instructions import PushState, PopState, ChangeState, PushMatrix, PopMatrix

def get_origin_value(origin, host_content):
    content = host_content
    if isinstance(origin, bytes):
        if origin == 'center':
            return (content._x + 0.5*content._size[0], content._y + 0.5*content._size[1])
        if origin == 'top_center':
            return (content._x + 0.5*content._size[0], content._y + content._size[1])
    elif isinstance(origin, tuple) or isinstance(origin, list):
        parent = content.parent
        w,h = parent.size[:]
        x,y = parent.pos[:]
        origin_x = x + origin[0]*w if origin[0] <= 1.0 else origin[0]
        origin_y = y + origin[1]*h if origin[1] <= 1.0 else origin[1]
        return origin_x, origin_y
    return (0,0)

class Transform(object):
    def __init__(self, content):
        self.host_content = content
        self._state_flg = False
        self._state_added_flg = False
        self._clear_all_flg = False
        self._scale_instruction = None
        self._rotate_instruction = None
        self._translate_instruction = None
        self._change_instruction = None
        self._opacity = 1.0
        self._scale_param =None
        self._rotate_param =None
        self._translate_param = None
        super(Transform, self).__init__()
        self._widons_size = Window.size[:]
        #把可视区域的z轴范围扩展到-400，400，这样就能看到绕x或y轴旋转的效果
        self._proj = Matrix().view_clip(0.0, self._widons_size[0], 0.0, self._widons_size[1], -400, 400, 0)
        #self._proj = Matrix().view_clip(-100.0, 100.0, -100.0, 100.0, 1.0, 100, 1)
        #self._proj = Matrix().look_at()
        #perspective = Matrix()
        #perspective.perspective(45, self._widons_size[1]/float(self._widons_size[0]), 1.0, 200)
        #self._proj = view_clip.multiply(perspective)
        #self.set_parameter(**kwargs)

    def set_parameter(self, **kwargs):
        #变换参数字典类型，格式{'opacity':1.0, 'scale':{'origin':0,'x':1.0,'y':1.0, 'z':0}, 'rotate':{'angle':0,'origin':0, 'axis':(0,0,1)}\
        # 'translate' :{'x':0, 'y':0, 'z':0}}
        #透明度
        opacity = kwargs.get('opacity', 1.0)
        if opacity != 1.0:
            #self._check_state_flag()
            self._opacity = opacity
            if self._change_instruction:
                self._change_instruction.changes = {'opacity': opacity}

        #缩放 origin 原点，x，y，z
        transform_kw = kwargs.get('scale', None)
        if transform_kw:
            origin = transform_kw.get('origin', None)
            x = transform_kw.get('x', 1.0)
            y = transform_kw.get('y', 1.0)
            z = transform_kw.get('z', 0.0)
            if self._scale_param:
                scale_origin = self._scale_param[3]
            else:
                scale_origin = origin
                if origin is None:
                    scale_origin = 'center'
            if self._scale_instruction:
                if origin:
                    if scale_origin != origin:
                        scale_origin = origin
                        org = get_origin_value(origin, self.host_content)
                        self._scale_instruction.origin = org
                self._scale_instruction.xyz = (x, y, z)
            self._scale_param = (x,y,z,scale_origin)

        #旋转 angle 角度， origin 原点，axis 坐标
        transform_kw = kwargs.get('rotate', None)
        if transform_kw:
            angle = transform_kw.get('angle', 0.0)
            axis = transform_kw.get('axis', None) #None为绕z轴旋转
            origin = transform_kw.get('origin', None)
            #self._check_state_flag()
            if self._rotate_param:
                rotate_origin = self._rotate_param[2]
                rotate_axis = self._rotate_param[1]
            else:
                rotate_origin = origin
                if origin is None:
                    rotate_origin = 'center'
                rotate_axis = axis
                if axis is None:
                    rotate_axis = (0,0,1)
            if self._rotate_instruction:
                if origin:
                    if rotate_origin != origin:
                        rotate_origin = origin
                        org = get_origin_value(origin, self.host_content)
                        self._rotate_instruction.origin = org
                if axis:
                    if rotate_axis != axis:
                        rotate_axis = axis
                        self._rotate_instruction.axis = axis
                self._rotate_instruction.angle = angle
            self._rotate_param = (angle, rotate_axis, rotate_origin)

        #平移 x，y，z
        transform_kw = kwargs.get('translate', None)
        if transform_kw:
            x = transform_kw.get('x', 0.0)
            y = transform_kw.get('y', 0.0)
            z = transform_kw.get('z', 0.0)
            #self._check_state_flag()
            if self._translate_instruction:
                self._translate_instruction.xyz = (x, y, z)
            self._translate_param = (x,y,z)

        if kwargs is not None:
            self._check_state_flag()

    def set_opacity(self, opacity):
        self._opacity = opacity
        self._change_instruction.changes = {'opacity': opacity}
        #没有更好的办法，只能通过平移z轴0来触发指令更新即间接调用flag_update。
        #不想改变kivy的源码
        self._translate_instruction.z = 0

    def set_scale(self, x, y, z = 1.0):
        self._scale_instruction.xyz = (x, y, z)

    def set_scale_origin(self, origin):
        self._scale_instruction.origin = origin

    def set_translate(self, x, y):
        self._translate_instruction.xy = (x, y)

    def set_rotate_angle(self, angle):
        self._rotate_instruction.angle = angle

    def set_rotate_origin(self, origin):
        self._rotate_instruction.origin = origin

    def set_rotate_axis(self,axis):
        self._rotate_instruction.axis = axis

    def _check_state_flag(self):
        if (self._scale_instruction is None) and  \
            (self._rotate_instruction is None) and \
            (self._translate_instruction is None) and (self._opacity == 1.0):
            self._state_flg = True
            self._clear_all_flg = True
            if self.host_content:
                #通知DIV，立刻把transform state 指令加入到opengl指令树里
                self.host_content.add_instruction()
                #print '--_check_state_flag---'

    def clear_state(self):
        self._opacity = 1.0
        self._scale_instruction = None
        self._rotate_instruction = None
        self._scale_param = None
        self._rotate_param =None
        self._translate_param = None
        self._state_flg = False
        self._clear_all_flg = True
        self._rotate_instruction = None
        if self.host_content:
            self.host_content.notify_property_changed()

    def push_transform_state(self, instruction_group):
        if self._clear_all_flg:
            instruction_group.clear()
        if self._state_flg:
            #状态指令没有添加就添加
            if not self._state_added_flg:
                st = PushState('projection_mat', 'opacity')
        
                instruction_group.add(st)
                self._change_instruction = ChangeState(projection_mat=self._proj, opacity=self._opacity)
                #self._change_instruction = ChangeState(opacity=self._opacity)
                instruction_group.add(self._change_instruction)
                st = PushMatrix()
                instruction_group.add(st)

                #添加translate instruction
                if self._translate_param is None:
                    self._translate_param = (0.0,0.0)
                self._translate_instruction = Translate(*self._translate_param)
                instruction_group.add(self._translate_instruction)

                #添加rotate instruction
                if self._rotate_param is None:
                    self._rotate_param = (0,(0,0,1),'center')
                angle, axis, origin = self._rotate_param
                origin = get_origin_value(origin, self.host_content)
                self._rotate_instruction = Rotate(angle=angle, origin=origin, axis=axis)
                instruction_group.add(self._rotate_instruction)

                #添加scale instruction
                if self._scale_param is None:
                    self._scale_param =(1.0,1.0,1.0,'center')
                x,y,z,origin = self._scale_param
                origin = get_origin_value(origin, self.host_content)
                self._scale_instruction = Scale(x,y,z,origin=origin)
                instruction_group.add(self._scale_instruction)

            elif self._change_instruction:
                #重新layout时，可视窗口和透明度需要同时更新。
                if self._widons_size != Window.size:
                    self._widons_size = Window.size[:]
                    self._proj = Matrix().view_clip(0.0, self._widons_size[0], 0.0, self._widons_size[1], -400, 400, 0)
                    self._change_instruction.changes = {'projection_mat': self._proj}
                if self._opacity != 1.0:
                    self._change_instruction.changes = {'opacity': self._opacity}
                if self._rotate_instruction:
                    self._rotate_instruction.origin = get_origin_value(self._rotate_param[2], self.host_content)
                if self._scale_instruction:
                    self._scale_instruction.origin = get_origin_value(self._scale_param[3], self.host_content)

            if self._clear_all_flg:
                self._clear_all_flg = False
                return False
            else:
                return self.host_content._added_flg

    def pop_transform_state(self, instruction_group):
        if self._state_flg:
            #状态指令没有添加就添加
            if not self._state_added_flg:
                st = PopMatrix()
                instruction_group.add(st)
                st = PopState('projection_mat', 'opacity')
                instruction_group.add(st)
                self._state_added_flg = True

